home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 October / CHIP Turkiye Ekim 2000.iso / prog / naps / 04 / setup.exe / Gnucleus / GnuControl.cpp < prev    next >
C/C++ Source or Header  |  2000-07-15  |  28KB  |  1,097 lines

  1. /********************************************************************************
  2.  
  3.     Gnucleus - A node application for the Gnutella network
  4.     Copyright (C) 2000 John Marshall
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     For support, questions, comments, etc...
  20.     E-Mail: 
  21.         swabby@c0re.net
  22.     
  23.     Address:
  24.         21 Cadogan Way
  25.         Nashua, NH, USA 03062 
  26.  
  27. ********************************************************************************/
  28.  
  29. // GnuControl.cpp : implementation file
  30. //
  31.  
  32. #include "stdafx.h"
  33. #include "GnuControl.h"
  34.  
  35. #include "Gnucleus.h"
  36. #include "GnucleusDoc.h"
  37.  
  38. #include "ViewSearch.h"
  39.  
  40. #include "GnuTransfer.h"
  41. #include "GnuHash.h"
  42. #include "GnuSock.h"
  43.  
  44. #ifdef _DEBUG
  45. #define new DEBUG_NEW
  46. #undef THIS_FILE
  47. static char THIS_FILE[] = __FILE__;
  48. #endif
  49.  
  50. IMPLEMENT_DYNCREATE(CGnuControl, CAsyncSocket)
  51.  
  52. /////////////////////////////////////////////////////////////////////////////
  53. // CGnuControl
  54.  
  55. CGnuControl::CGnuControl()
  56. {
  57.     m_Initialize();
  58. }
  59.  
  60. CGnuControl::CGnuControl(CGnucleusDoc *DocLink)
  61. {
  62.     m_Initialize();
  63.     
  64.     Doc = DocLink;
  65. }
  66.  
  67. void CGnuControl::m_Initialize (void)
  68. {
  69.     NodeList = NULL;
  70.     TransferList = NULL;
  71.  
  72.     CoCreateGuid(&ClientGUID);
  73.  
  74.     BytesIn = 0;
  75.     BytesOut = 0;
  76.  
  77.     totalPings            = 0;
  78.     totalPongs            = 0;
  79.     totalPushes            = 0;
  80.     totalUnknowns        = 0;
  81.     totalQueries        = 0;
  82.     totalQueryReplies    = 0;
  83.  
  84.     totalTTLs            = 0;
  85.     totalTTLsBig        = 0;
  86.  
  87.     totalHops            = 0;
  88.     totalHopsBig        = 0;
  89.  
  90.     RunningThreads = 0;
  91.  
  92.     m_dwBytesPerSecIn = m_dwBytesPerSecOut = 0;
  93.     m_dwTotalBytesIn = m_dwTotalBytesOut = 0;
  94.  
  95.     // Create listen socket on random port 2,500 - 25,000
  96.     srand( (unsigned)time( NULL ) );
  97.     localPort = rand() % 22500 + 2500;
  98.  
  99.     localHost = "127.0.0.1";
  100.  
  101.     m_QueriesSearchThreadHandle = AfxBeginThread(CGnuControl::staticQueriesSearchThread, this, THREAD_PRIORITY_BELOW_NORMAL);
  102. }
  103.  
  104. CGnuControl::~CGnuControl()
  105. {
  106.     // indicate to the thread that we are exiting
  107.     m_QueriesSearchThreadHandle->m_bAutoDelete = FALSE;
  108.     m_EventQueriesEND.SetEvent();
  109.  
  110.     // wait for the thread to exit
  111.     WaitForSingleObject(m_QueriesSearchThreadHandle->m_hThread, INFINITE);
  112.     delete m_QueriesSearchThreadHandle;
  113.     
  114.     CGnuSock *deadNode = NULL;
  115.  
  116.     while(NodeList != NULL)
  117.     {
  118.         deadNode = NodeList;
  119.         NodeList = NodeList->next;
  120.  
  121.         delete deadNode;
  122.     }
  123.  
  124.     CGnuTransfer *deadTransfer = NULL;
  125.  
  126.     while(TransferList != NULL)
  127.     {
  128.         deadTransfer = TransferList;
  129.         TransferList = TransferList->next;
  130.  
  131.         delete deadTransfer;
  132.     }
  133. }
  134.  
  135. // Do not edit the following lines, which are needed by ClassWizard.
  136. #if 0
  137. BEGIN_MESSAGE_MAP(CGnuControl, CAsyncSocket)
  138.     //{{AFX_MSG_MAP(CGnuControl)
  139.     //}}AFX_MSG_MAP
  140. END_MESSAGE_MAP()
  141. #endif    // 0
  142.  
  143. /////////////////////////////////////////////////////////////////////////////
  144. // CGnuControl member functions
  145.  
  146. BOOL CGnuControl::AddNode(CString Host, CString Port)
  147. {
  148.     DWORD dPort = atol(Port);
  149.  
  150.     CGnuSock *newNode = new CGnuSock(this);
  151.  
  152.     //Attempt to connect to node
  153.     newNode->Create();
  154.     if (!newNode->Connect(Host, dPort))
  155.     { // DW This keeps from adding unreachable connections
  156.         DWORD dwError = newNode->GetLastError();
  157.         if (dwError != WSAEWOULDBLOCK)
  158.         {
  159.             delete(newNode);
  160.             return FALSE;
  161.         }
  162.     }
  163.   
  164.  
  165.     // Add the node to the linked list
  166.     if(NodeList != NULL)
  167.         newNode->next = NodeList;
  168.         
  169.     NodeList = newNode;
  170.  
  171.     newNode->Host = Host;
  172.     newNode->Port = Port;
  173.  
  174.     return TRUE;
  175. }
  176.  
  177. void CGnuControl::RemoveNode(CString Host, CString Port)
  178. {
  179.     CGnuSock *pFront = NodeList;
  180.     CGnuSock *pBack = NULL;
  181.     CGnuSock *deadNode;
  182.  
  183.     // While list isn't empty
  184.     while(pFront != NULL)
  185.     {
  186.         // If its at the beginning of the list
  187.         if(NodeList != NULL && pBack == NULL)
  188.         {
  189.             if(pFront->Host == Host && pFront->Port == Port)
  190.             {
  191.                 deadNode = NodeList;
  192.                 NodeList = NodeList->next;
  193.                 pFront = NodeList;
  194.     
  195.                 deadNode->Close();        // need this to give resources back to the system
  196.                 deadNode->CleanUp();
  197.  
  198.                 delete deadNode;
  199.                 deadNode = NULL;
  200.             }
  201.         }
  202.         // If its at the middle or end of the list
  203.         else if(pFront != NULL && pFront->Host == Host && pFront->Port == Port)
  204.         {
  205.             deadNode = pFront;
  206.             pFront = deadNode->next;
  207.             pBack->next = deadNode->next;
  208.  
  209.             deadNode->Close();
  210.             deadNode->CleanUp();
  211.  
  212.             delete deadNode;
  213.             deadNode = NULL;
  214.         }
  215.  
  216.         pBack = pFront;
  217.         if(pFront != NULL)
  218.             pFront = pFront->next;
  219.     }
  220. }
  221.  
  222. CGnuSock* CGnuControl::GetNode(CString HostPort)
  223. {
  224.             
  225.     int index = HostPort.Find(":", 0);
  226.     CString Host = HostPort.Mid(0, index);
  227.     CString Port = HostPort.Mid(index + 1, HostPort.GetLength() - index);
  228.  
  229.     CGnuSock *p = NodeList;
  230.  
  231.     while(p != NULL)
  232.     {
  233.         if(p->Host == Host && p->Port == Port)
  234.             return p;
  235.  
  236.         p = p->next;
  237.     }
  238.  
  239.     return NULL;
  240. }
  241.  
  242. void CGnuControl::OnAccept( int nErrorCode )
  243. {
  244.     CGnuSock *newNode = new CGnuSock(this);
  245.     Accept(*newNode);
  246.  
  247.     if(NodeList != NULL)
  248.         newNode->next = NodeList;
  249.  
  250.     NodeList = newNode;
  251.  
  252.     UINT trash;
  253.     newNode->GetPeerName(newNode->Host, trash);
  254.     newNode->Port = "Inbound";
  255.  
  256.     /*
  257.     if(Doc->m_DropForIncoming || Doc->m_MonitorType == 0)
  258.     {    
  259.         if(NodeList != NULL)
  260.             newNode->next = NodeList;
  261.  
  262.         NodeList = newNode;
  263.  
  264.         UINT trash;
  265.         newNode->GetPeerName(newNode->Host, trash);
  266.         newNode->Port = "Inbound";
  267.     }
  268.  
  269.     else if(Doc->m_MonitorType == 3 ||
  270.            (Doc->m_MonitorType == 2 && Doc->Connections.GetCount() < Doc->m_ConnectNum) ||
  271.            (Doc->m_MonitorType == 1 && Doc->Connections.GetCount() < Doc->m_ConnectNum - 1))
  272.     {
  273.         
  274.         if(NodeList != NULL)
  275.             newNode->next = NodeList;
  276.  
  277.         NodeList = newNode;
  278.  
  279.         UINT trash;
  280.         newNode->GetPeerName(newNode->Host, trash);
  281.         newNode->Port = "Inbound";
  282.     }
  283.     else
  284.     {
  285.         newNode->Close();
  286.         newNode->CleanUp();
  287.  
  288.         delete newNode;
  289.     }*/
  290. }
  291.  
  292. void CGnuControl::Pass_Raw(CGnuSock *exception, byte *packet, int length)
  293. {
  294.     CGnuSock *p = NodeList;
  295.  
  296.     while(p != NULL)
  297.     {
  298.         if(p != exception && p->Connected)
  299.         {
  300.             p->Send(packet, length);
  301.             BytesOut += length;
  302.         }
  303.         p = p->next;
  304.     }
  305. }
  306.  
  307. void CGnuControl::Broadcast_Ping(packet_Ping *Ping, int length, CGnuSock *exception)
  308. {
  309.     CGnuSock *p = NodeList;
  310.  
  311.     while(p != NULL)
  312.     {
  313.         if(p != exception && p->Connected)
  314.         {
  315.             p->Send((byte *) Ping, length);
  316.             BytesOut += length;
  317.         }
  318.  
  319.         p = p->next;
  320.     }
  321. }
  322.  
  323. void CGnuControl::Broadcast_Query(packet_Query *Query, int length, CGnuSock *exception)
  324. {
  325.     // NOTE:  Could use some flood protection
  326.  
  327.     CGnuSock *p = NodeList;
  328.  
  329.     while(p != NULL)
  330.     {
  331.         if(p != exception && p->Connected)
  332.         {
  333.             p->Send((byte *) Query, length);
  334.             BytesOut += length;
  335.         }
  336.         p = p->next;
  337.     }
  338. }
  339.  
  340. void CGnuControl::Route_Pong(packet_Pong *Pong, int length, key_data *key)
  341. {
  342.     CGnuSock *p = NodeList;
  343.  
  344.     while(p != NULL)
  345.     {
  346.         if(p == key->Origin && p->Connected)
  347.         {
  348.             p->Send((byte *) Pong, length);
  349.             BytesOut += length;
  350.         }
  351.  
  352.         p = p->next;
  353.     }
  354. }
  355.  
  356. void CGnuControl::Route_QueryReply(packet_QueryReply *QueryReply, int length, key_data *key)
  357. {
  358.     CGnuSock *p = NodeList;
  359.  
  360.     while(p != NULL)
  361.     {
  362.         if(p == key->Origin && p->Connected)
  363.         {
  364.             p->Send((byte *) QueryReply, length);
  365.             BytesOut += length;
  366.         }
  367.  
  368.         p = p->next;
  369.     }
  370. }
  371.  
  372. void CGnuControl::Route_Push(packet_Push *Push, int length, key_data *key)
  373. {
  374.     CGnuSock *p = NodeList;
  375.  
  376.     while(p != NULL)
  377.     {
  378.         if(p == key->Origin && p->Connected)
  379.         {
  380.             p->Send((byte *) Push, length);
  381.             BytesOut += length;
  382.         }
  383.  
  384.         p = p->next;
  385.     }
  386. }
  387.  
  388. void CGnuControl::StartListening()
  389. {
  390.     CString Host, Port, Title;
  391.     int decimal, sign;
  392.  
  393.     Close();
  394.  
  395.     if(Create(localPort))
  396.     {
  397.         Listen();
  398.  
  399.         Port = _fcvt(localPort, 0, &decimal, &sign);
  400.  
  401.         Title = "Gnucleus on port " + Port;
  402.  
  403.         AfxGetApp()->m_pMainWnd->ModifyStyle(FWS_ADDTOTITLE, 0);
  404.         AfxGetApp()->m_pMainWnd->SetWindowText(Title);
  405.     }
  406. }
  407.  
  408. // File Transfer Part of the code
  409. void CGnuControl::AddTransfer(QueryItem File, SOCKET sock)
  410. {
  411.     CGnuTransfer *newTransfer = new CGnuTransfer(this);
  412.  
  413.     if (!sock)
  414.     {
  415.         //Attempt to connect to node
  416.         newTransfer->Create();
  417.     }
  418.     else
  419.     {
  420.         newTransfer->Attach (sock);
  421.     }
  422.  
  423.     // Add the transfer to the linked list
  424.     if(TransferList != NULL)
  425.         newTransfer->next = TransferList;
  426.         
  427.     TransferList = newTransfer;
  428.  
  429.     newTransfer->Handle = File.Handle;
  430.     newTransfer->Status = File.Status;
  431.     newTransfer->FileInfo = File;
  432.     newTransfer->Type = File.TransferType;
  433.     newTransfer->BytesCompleted = File.BytesCompleted;
  434.     newTransfer->FileSize = File.Size;
  435.  
  436.     if (sock)    // It's already connected and waiting for the GET request!
  437.     {
  438.         if(newTransfer->Type == 'D')
  439.             newTransfer->OnConnect (0);
  440.  
  441.         if(newTransfer->Type == 'U')
  442.         {
  443. /*
  444.             newTransfer->FileSize = File.Size;
  445.             newTransfer->BytesCompleted = File.BytesCompleted;
  446. */
  447.         }
  448.     }
  449. }
  450.  
  451. void CGnuControl::RemoveTransfer(int row, char type)
  452. {
  453.     CGnuTransfer *pFront = TransferList;
  454.     CGnuTransfer *pBack = NULL;
  455.     CGnuTransfer *deadTransfer;
  456.  
  457.     // While list isn't empty
  458.     while(pFront != NULL)
  459.     {
  460.         // If its at the beginning of the list
  461.         if(TransferList != NULL && pBack == NULL)
  462.         {
  463.             if(pFront->Handle == row && pFront->Type == type)
  464.             {
  465.                 deadTransfer = TransferList;
  466.                 TransferList = TransferList->next;
  467.                 pFront = TransferList;
  468.     
  469.                 deadTransfer->Close();
  470.  
  471.                 delete deadTransfer;
  472.                 deadTransfer = NULL;
  473.             }
  474.         }
  475.         // If its at the middle or end of the list
  476.         else if(pFront != NULL && pFront->Handle == row && pFront->Type == type)
  477.         {
  478.             deadTransfer = pFront;
  479.             pFront = deadTransfer->next;
  480.             pBack->next = deadTransfer->next;
  481.  
  482.             deadTransfer->Close();
  483.  
  484.             delete deadTransfer;
  485.             deadTransfer = NULL;
  486.         }
  487.  
  488.         pBack = pFront;
  489.         if(pFront != NULL)
  490.             pFront = pFront->next;
  491.     }
  492. }
  493.  
  494. std::map <GUID, QueryItem, CompareGuids> g_pushList;
  495.  
  496. void CGnuControl::NewPushRequest(QueryItem File)
  497. {
  498.     
  499.     // ClientID's are in their own table
  500.  
  501.     key_data *ClientID = HashClientTable.FindValue(&File.Guid);
  502.  
  503.     // ClientID not found in table
  504.     if(ClientID == NULL)
  505.         return;
  506.         
  507.     // Build the packet
  508.     packet_Push push;
  509.  
  510.     ::memset (&push, 0, sizeof (push));
  511.     ::CoCreateGuid (&push.Header.Guid);
  512.     
  513.     push.Header.Function = 0x40;
  514.     push.Header.TTL = 7;
  515.     push.Header.Hops = 0;
  516.     push.Header.Payload = flipX(makeX(26));
  517.  
  518.     push.ClientID = ClientID->Guid;
  519.     push.Index = flipX(makeX(File.Index));
  520.  
  521.     if( IPtoStr(Doc->m_ForceIP) != "0.0.0.0")
  522.         push.Host = Doc->m_ForceIP;
  523.     else
  524.         push.Host = StrtoIP(localHost);
  525.  
  526.     push.Port = localPort;
  527.     try
  528.     {
  529.         ClientID->Origin->Send((byte *) &push, 23 + 26);
  530.     }
  531.     catch ( ... )    // catch the bad Origin pointer for now
  532.     {
  533.         return;
  534.     }
  535.  
  536.  
  537.     // Save the guid, the connecting host will send us it
  538.     GUID temp_guid;
  539.  
  540.     temp_guid = push.ClientID;
  541.  
  542.     temp_guid.Data1 ^= File.Index;            // We can't use the straight guid
  543.     temp_guid.Data2 ^= (File.Index << 1);    // just xor some of the values in the guid
  544.  
  545.     g_pushList[temp_guid] = File;
  546. }
  547.  
  548. CGnuTransfer* CGnuControl::GetTransfer(int row, char type)
  549. {
  550.     CGnuTransfer *pos = TransferList;
  551.  
  552.     while(pos != NULL)
  553.     {
  554.         if(pos->Handle == row && pos->Type == type)
  555.             return pos;
  556.         
  557.         pos = pos->next;
  558.     }
  559.  
  560.     return NULL;
  561. }
  562.  
  563. DWORD CGnuControl::GetHostCount()
  564. {
  565.     DWORD Total = 0;
  566.  
  567.     CGnuSock *p = NodeList;
  568.  
  569.     while(p != NULL)
  570.     {
  571.         if(p->Connected)
  572.             Total += p->TotalRemoteHosts() + 1;
  573.  
  574.         p = p->next;
  575.     }
  576.  
  577.     return Total;
  578. }
  579.  
  580. ////////////////////////////////////////////////////////////
  581. //! author="Nathan Brown"
  582. //
  583. //: Pushes query request to queue for thread.
  584. //    Use this for variable from CGnuSock object
  585. void CGnuControl::PushQueryToQueue(CGnuSock * _lp_sock)
  586. {
  587.     // protect query list from access when adding
  588.     bool bSucess = true;
  589.     SearchQueryItem search_item;
  590.  
  591.  
  592.     if(! AfxIsValidAddress( _lp_sock, sizeof(CGnuSock)))
  593.     {
  594. //        ASSERT(FALSE);
  595.         return;
  596.     }
  597.  
  598.     try        // don't trust pointers
  599.     {
  600.         search_item.ConnectedSock    = _lp_sock;
  601.         search_item.SearchString    = _lp_sock->CurrentSearch;
  602.         search_item.ClientGuid        = _lp_sock->GnuComm->ClientGUID;
  603.         search_item.Origin            = _lp_sock->CurrentOrigin;
  604.         search_item.Host            = StrtoIP(_lp_sock->GnuComm->localHost);
  605.         search_item.localPort        = _lp_sock->GnuComm->localPort;
  606.         search_item.SearchString.MakeLower();
  607.  
  608.         // Lock, push, and unlock
  609.         m_QueryListCriticalSection.Lock();
  610.         m_SearchQueries.push_back(search_item);
  611.         m_QueryListCriticalSection.Unlock();
  612.     }
  613.     catch ( ... )    // bad pointer
  614.     {
  615.         // failed
  616.         bSucess = false;
  617.     }
  618.  
  619.  
  620.     // let the thread know that there is a item
  621.     if(bSucess)
  622.         m_EventQueriesWaiting.SetEvent();
  623. }
  624.  
  625. ////////////////////////////////////////////////////////////
  626. //! author="Nathan Brown"
  627. //
  628. //: Pops query off of queue for thread to start search
  629. bool CGnuControl::PopQueryFromQueue(SearchQueryItem & _search_item)
  630. {
  631.     bool bResult = true;
  632.  
  633.     if( m_SearchQueries.empty())
  634.         return false;
  635.     else
  636.     {
  637.         // protect query list from access when removing
  638.         m_QueryListCriticalSection.Lock();
  639.         
  640.         SearchQueryItem * search_item = &m_SearchQueries.front();
  641.  
  642.         // copy the items to the waiting struct
  643.         _search_item.ConnectedSock    = search_item->ConnectedSock;
  644.         _search_item.SearchString    = search_item->SearchString;
  645.         _search_item.ClientGuid        = search_item->ClientGuid;
  646.         _search_item.Origin            = search_item->Origin;
  647.         _search_item.Host            = search_item->Host;
  648.         _search_item.localPort        = search_item->localPort;
  649.  
  650.         // remove from stack
  651.         m_SearchQueries.pop_front();
  652.  
  653.         // release the lock.
  654.         m_QueryListCriticalSection.Unlock();
  655.         
  656.         return bResult;
  657.     }
  658.  
  659.  
  660. }
  661.  
  662. struct query_search_word
  663. {
  664.     query_search_word(){};
  665.     query_search_word(DWORD _query_num, CString & _searchWord) 
  666.         : query_num(_query_num), searchWord(_searchWord)    {};
  667.     
  668.     DWORD query_num;
  669.     CString searchWord;
  670. };
  671.  
  672. struct query_result_match
  673. {
  674.     query_result_match(DWORD _query_num, QueryResult _query_result) 
  675.         : query_num(_query_num), query_result(_query_result)    {};
  676.     
  677.     DWORD        query_num;
  678.     QueryResult query_result;
  679. };
  680.  
  681. ////////////////////////////////////////////////////////////
  682. //! author="Nathan Brown"
  683. //
  684. //: Thread for all connections to search for matches to queries
  685. UINT CGnuControl::staticQueriesSearchThread(LPVOID _lpv_control)
  686. {
  687.     // Call class member so it's localized.
  688.     return ((CGnuControl *)_lpv_control)->QueriesSearchThread();
  689. }
  690.  
  691. // localized class thread
  692. UINT CGnuControl::QueriesSearchThread()
  693. {
  694.     SearchQueryItem query_item_temp;
  695.     query_item_temp.bIsMatch = 0;
  696.  
  697.     // rejected queries for a file
  698.     bool b_table_not_current_file[50];
  699.     DWORD dw_table_num_of_matches[50];
  700.  
  701.     DWORD i_num_queries_at_once = 0;
  702.  
  703.     // for before splitting up among queries
  704.     std::vector <query_result_match> query_match;
  705.     // result of one query
  706.     std::queue <QueryResult> resultQueue;
  707.  
  708.     query_search_word query_word_temp;
  709.  
  710.     std::vector<SharedFile>::iterator itName;
  711.     std::vector<DWORD>::iterator itSize;
  712.     std::vector<SearchQueryItem>::iterator it_queries_vector;
  713.     std::vector<query_search_word>::iterator it_query_search;
  714.  
  715.     // Split up the search string once so we don't do it for every file
  716.     std::vector<query_search_word> searchWords;
  717.  
  718.     // vector for matching results to who requested it.
  719.     std::vector<SearchQueryItem> queries_vector;
  720.  
  721.     DWORD hits = 0;
  722.  
  723.     // for multilock
  724.     CSyncObject * query_events[2] = { &m_EventQueriesEND , 
  725.         &m_EventQueriesWaiting  };        // order does matter
  726.     
  727.     CMultiLock  query_events_multi_lock(query_events, 2, FALSE);
  728.  
  729.     // *start loop
  730.     for(;;)
  731.     {
  732.  
  733.         // *check semaphore for any jobs waiting, wait until there is one
  734.         // *also make sure we arn't supposed to be shutting down.
  735.  
  736.         if(query_events_multi_lock.Lock(INFINITE, FALSE, 0) == WAIT_OBJECT_0)
  737.             // Queries end was called, exit.
  738.             return 0;        // simple as that
  739.  
  740.         // else go on to handle a search event
  741.         m_EventQueriesWaiting.ResetEvent();
  742.  
  743.  
  744.         // *check query queue, pull items off.
  745.  
  746.         while( PopQueryFromQueue(query_item_temp) && i_num_queries_at_once < 50)
  747.         {
  748.             query_word_temp.query_num = i_num_queries_at_once;
  749.             queries_vector.push_back(query_item_temp);
  750.  
  751.             ++i_num_queries_at_once;
  752.  
  753.             // we arn't using these delemiters, so convert to one we are.
  754.             query_item_temp.SearchString.Replace("*", " ");
  755.             query_item_temp.SearchString.Replace("+", " ");
  756.             
  757.             // *split strings into seperate items (delemited by space)
  758.             // *parse string and put into search vector.
  759.             while ( !query_item_temp.SearchString.IsEmpty() )
  760.             {
  761.                 int idq = query_item_temp.SearchString.Find ("\"");
  762.                 int idx = query_item_temp.SearchString.Find (" ");
  763.  
  764.                 if (idx != -1)
  765.                 {
  766.                     if (idx > 0)
  767.                     {
  768.                         query_word_temp.searchWord = query_item_temp.SearchString.Left (idx);
  769.                         searchWords.push_back (query_word_temp);
  770.                     }
  771.  
  772.                     query_item_temp.SearchString = query_item_temp.SearchString.Mid (idx+1);
  773.                 }
  774.                 else
  775.                 {
  776.                     query_word_temp.searchWord = query_item_temp.SearchString;
  777.                     searchWords.push_back (query_word_temp);
  778.  
  779.                     break;
  780.                 }
  781.             }
  782.         }
  783.         
  784.         // *check for file table lock, wait until available
  785.         Doc->LockUploadData (false);
  786.         if(! Doc->SharedFiles.empty())
  787.         {
  788.             // *search file table
  789.             for(int ia = 0; ia < i_num_queries_at_once; ++ia)
  790.                 dw_table_num_of_matches[ia] = 0;
  791.  
  792.  
  793.             // Determine if we have any files that match the search
  794.             DWORD loop;
  795.             for(loop = 0, itName = Doc->SharedFiles.begin(), itSize = Doc->SharedSizes.begin(); 
  796.                 itName != Doc->SharedFiles.end(), itSize != Doc->SharedSizes.end(); 
  797.                 loop++, itName++, itSize++)
  798.             {
  799.                 CString CompareFile( (*itName).FileDir );
  800.                 //CString FileToSend = CompareFile.Mid( CompareFile.ReverseFind('\\') + 1);
  801. //                CString FileToSend = (*itName).FileName;
  802.  
  803.  
  804.                 for(int ib = 0; ib < i_num_queries_at_once; ++ib)
  805.                 {
  806.                     b_table_not_current_file[ib] = false;
  807.                     if( dw_table_num_of_matches[ib] > 
  808.                             (Doc->m_MaxReplies ? Doc->m_MaxReplies : 563)) // limit replies anyways.
  809.                         b_table_not_current_file[ib] = true;                // quick hack for now.  probably remove the file from the list later.
  810.                 }
  811.                 
  812.                 DWORD length = 50;
  813.  
  814.                 // break directory off of compare string
  815.                 int slashes = 0;
  816.                 for(int i = CompareFile.GetLength() - 1; i > 0 && slashes < 2; i--)
  817.                     if( CompareFile.GetAt(i) == '\\' )
  818.                         slashes++;
  819.  
  820.                 CompareFile = CompareFile.Mid(i + 2, CompareFile.GetLength() - i);
  821.  
  822.  
  823.                 int Found=0;
  824.  
  825.                 // look for matches to the words
  826.                  
  827.                 for(it_query_search = searchWords.begin (); it_query_search != searchWords.end (); ++it_query_search)
  828.                 {
  829.                     if( b_table_not_current_file[(*it_query_search).query_num] == false
  830.                         && CompareFile.Find ((*it_query_search).searchWord) != -1)
  831.                     {
  832.                         Found++;
  833.                     }
  834.                     else
  835.                     {
  836.                         // this query is rejected
  837.                         b_table_not_current_file[(*it_query_search).query_num] = true;
  838.                     }
  839.                 }
  840.  
  841.                 if(Found)
  842.                 {
  843.                     // add to result queue if there is a match for a query
  844.                     for(DWORD i = 0; i < i_num_queries_at_once; ++i)
  845.                     {
  846.  
  847.                         if ( b_table_not_current_file[i] == false )
  848.                         {
  849.                             // add to result queue
  850.                             query_match.push_back( query_result_match(i, QueryResult (loop, *itSize, (*itName).FileName ) ) );
  851.                             // indicate match
  852.                             queries_vector[i].bIsMatch = true;
  853.                         
  854.                             // increment the counters for number of results
  855.                             dw_table_num_of_matches[i]++;
  856.                             
  857.                         }
  858.                     }
  859.                 }                
  860.             }
  861.  
  862.         }
  863.         
  864.  
  865.         // *build replies per query
  866.         std::vector<query_result_match>::iterator it;
  867.         int i_count = 0;
  868.         if(! queries_vector.empty())
  869.         {
  870.             for( it_queries_vector = queries_vector.begin(); it_queries_vector != queries_vector.end(); it_queries_vector++)
  871.             {
  872.                 // is signaled as having results?
  873.                 if( (*it_queries_vector).bIsMatch )
  874.                 {
  875.                     
  876.                     for(it = query_match.begin(); it != query_match.end(); it++)
  877.                     {
  878.                         if( (*it).query_num == i_count )
  879.                         {
  880.                             // add result to queue to send
  881.                             QueryResult query_item_temp_ = ((*it).query_result);
  882.                             resultQueue.push( query_item_temp_ );
  883.                         }
  884.                     }
  885.  
  886.                     // Send results  -  We don't need to try and catch this because the SendFileResults function does that for us.
  887.                     (*it_queries_vector).ConnectedSock->SendFileResults(resultQueue, (*it_queries_vector).Origin );
  888.  
  889.                     // empty the queue incase it wasn't already done
  890.                     while(! resultQueue.empty())
  891.                         resultQueue.pop();
  892.                 }
  893.                 i_count++;
  894.             }
  895.         }
  896.  
  897.         // unlock table database,  we are done with it.
  898.         Doc->UnlockUploadData (false);
  899.  
  900.         
  901.         // *clear various items.
  902.         i_num_queries_at_once = 0;
  903.         query_match.clear();
  904.         searchWords.clear();
  905.         queries_vector.clear();
  906.         hits = 0;
  907.  
  908.  
  909.         // *repeate and wait for next item.
  910.  
  911.     }
  912.  
  913.     return 0;
  914. }
  915.  
  916.  
  917. ////////////////////////////////////////////////////////////
  918. //! author="Nathan Brown"
  919. //
  920. //: Updates various aspects of each sock and manages bandwidth limiting.
  921. void CGnuControl::OnTimer()
  922. {
  923.  
  924.     // * add up all the in and out going traffic, compair to the last saved amount
  925.     // * and calculate a bit rate.
  926.  
  927.     DWORD    dw_bytes_in = 0, dw_bytes_out = 0;
  928.  
  929.     int num_transfers = 0, num_nodes =  0;
  930.  
  931.     float balance_transfers_at_percent = (.5) ;
  932.  
  933.     CGnuSock *p_soc = NodeList;
  934.     CGnuTransfer *p_tns = TransferList;
  935.  
  936.     for(p_soc = NodeList; p_soc != NULL;)
  937.     {
  938.         num_nodes++;
  939.  
  940.         dw_bytes_in += p_soc->m_dwBytesIn;
  941.         p_soc->m_dwTotalBytesIn += p_soc->m_dwBytesIn;
  942.  
  943.         dw_bytes_out += p_soc->m_dwBytesOut;
  944.         p_soc->m_dwTotalBytesOut += p_soc->m_dwBytesOut;
  945.         
  946.         p_soc = p_soc->next;
  947.     }
  948.  
  949.  
  950.     for(p_tns = TransferList; p_tns != NULL;)
  951.     {
  952.         num_transfers++;
  953.  
  954.         dw_bytes_in += p_tns->m_dwBytesIn;
  955.         p_tns->m_dwTotalBytesIn += p_tns->m_dwBytesIn;
  956.  
  957.         dw_bytes_out += p_tns->m_dwBytesOut;
  958.         p_tns->m_dwTotalBytesOut += p_tns->m_dwBytesOut;
  959.         
  960.         p_tns = p_tns->next;
  961.     }
  962.  
  963.     // calculate bit rate, weighted 1:2 to the previous sample
  964.     m_dwBytesPerSecIn = (dw_bytes_in + m_dwBytesPerSecIn*2) / 3;
  965.     m_dwBytesPerSecOut = (dw_bytes_out + m_dwBytesPerSecOut*2) / 3;
  966.  
  967.     if(num_nodes)
  968.     {
  969.         int extra_from_last_cycle = 0;
  970.         DWORD dw_bytes_out_per_soc = 0;
  971.         DWORD dw_bytes_out_per_tns = 0;
  972.         DWORD dw_bytes_out_per_thread_plus = 0;
  973.         DWORD dw_bytes_in_per_soc = 0;
  974.         DWORD dw_bytes_in_per_tns = 0;
  975.         DWORD dw_bytes_in_per_thread_plus = 0;
  976.         DWORD dw_bytes_out_total = 0;
  977.         DWORD dw_bytes_in_total = 0;
  978.         
  979.         // * slice up an in/out allowance among the sockets.
  980.         if(Doc->m_LimitTotal)
  981.         {
  982.             dw_bytes_out_total = Doc->m_LimitTotal * 1024;
  983.             dw_bytes_in_total = dw_bytes_out_total - dw_bytes_in;
  984.             
  985.             extra_from_last_cycle = Doc->m_LimitTotal * 1024 / 2 - dw_bytes_out;            // get any unused portion from the last time slice
  986.             extra_from_last_cycle = extra_from_last_cycle > 0 ? extra_from_last_cycle : 0;    // keep it from being negative
  987.  
  988.             dw_bytes_out_per_soc = (Doc->m_LimitTotal * 1024 / (num_nodes * 2)) + extra_from_last_cycle;    // limit each sock to just a fraction
  989.             dw_bytes_out_per_soc -= num_transfers ? dw_bytes_out_per_soc * balance_transfers_at_percent : 0;        // keep a good chunk for transfers
  990.  
  991.             dw_bytes_in_per_soc = dw_bytes_out_per_soc;
  992.  
  993.             dw_bytes_out_per_tns = balance_transfers_at_percent * Doc->m_LimitTotal * 1024 / (num_nodes * 2);    // limit each sock to just a fraction
  994.             dw_bytes_in_per_tns = dw_bytes_out_per_soc;
  995.         }
  996.         if(Doc->m_LimitUp)
  997.         {
  998.             dw_bytes_out_total = Doc->m_LimitUp * 1024 - (Doc->m_LimitTotal ? dw_bytes_in / 2 : 0);
  999.  
  1000.             extra_from_last_cycle = Doc->m_LimitUp * 1024 - dw_bytes_out;            // get any unused portion from the last time slice
  1001.             extra_from_last_cycle = extra_from_last_cycle > 0 ? extra_from_last_cycle : 0;    // keep it from being negative
  1002.  
  1003.             dw_bytes_out_per_soc = (Doc->m_LimitUp * 1024 / num_nodes) + extra_from_last_cycle;    // limit each sock to just a fraction
  1004.             dw_bytes_out_per_soc -= num_transfers ? dw_bytes_out_per_soc * balance_transfers_at_percent : 0;        // keep a good chunk for transfers
  1005.  
  1006.             dw_bytes_out_per_tns = balance_transfers_at_percent * Doc->m_LimitUp * 1024 / num_nodes;    // limit each sock to just a fraction
  1007.         }
  1008.  
  1009.         dw_bytes_out_per_thread_plus = (DWORD)((double)(dw_bytes_out_per_soc) * 0.20);    // add a buffer in case a sock need to catch up.
  1010.         dw_bytes_in_per_thread_plus = (DWORD)((double)(dw_bytes_in_per_soc) * 0.20);    // add a buffer in case a sock need to catch up.
  1011.  
  1012.         for(p_soc = NodeList; p_soc != NULL;)
  1013.         {
  1014.             // if this thread is hitting it's allotment, pull it back.
  1015.             if( p_soc->m_dwBytesOut >= p_soc->m_dwByteAllottmentOut)
  1016.                 p_soc->m_dwByteAllottmentOut = dw_bytes_out_per_soc;
  1017.             else
  1018.                 p_soc->m_dwByteAllottmentOut = dw_bytes_out_per_thread_plus;
  1019.  
  1020.             // same for incomming traffic
  1021.             if( p_soc->m_dwBytesIn >= p_soc->m_dwByteAllottmentIn)
  1022.                 p_soc->m_dwByteAllottmentIn = dw_bytes_in_per_soc;
  1023.             else
  1024.                 p_soc->m_dwByteAllottmentIn = dw_bytes_in_per_thread_plus;
  1025.  
  1026.             // weed any getting way behind in their queue
  1027.             if(p_soc->m_iSizeOfPacketQueue > 100)
  1028.             {
  1029.                 CString Host = p_soc->Host;
  1030.                 CString Port = p_soc->Port;
  1031.                 p_soc = p_soc->next;            // avoid trying to access the pointer to get next after it's gone
  1032.                 RemoveNode(Host, Port);
  1033.                 if(Doc->m_ConnectNum > 2)        // see if we can lower the target amount of clients
  1034.                     Doc->m_ConnectNum--;
  1035.             }
  1036.             else
  1037.                 p_soc = p_soc->next;
  1038.         }
  1039.         
  1040.         dw_bytes_out_per_thread_plus = (DWORD)((double)(dw_bytes_out_per_tns) * 0.20);    // add a buffer in case a sock need to catch up.
  1041.         dw_bytes_in_per_thread_plus = (DWORD)((double)(dw_bytes_in_per_tns) * 0.20);    // add a buffer in case a sock need to catch up.
  1042.  
  1043.         for(p_tns = TransferList; p_tns != NULL;)
  1044.         {
  1045.             // if this thread is hitting it's allotment, give it a little more slack
  1046.             if( dw_bytes_out_total >= p_tns->m_dwByteAllottmentOut
  1047.                 && dw_bytes_out_total > dw_bytes_out)
  1048.                 p_tns->m_dwByteAllottmentOut += (dw_bytes_out_total - dw_bytes_out) * .20;        // increase by 20% of the difference
  1049.             else if(dw_bytes_out_total < dw_bytes_out)        // it's way over, drop it down
  1050.                 p_tns->m_dwByteAllottmentOut = dw_bytes_out_per_thread_plus;
  1051.             else    // lower bar a little.
  1052.             {
  1053.                 p_tns->m_dwByteAllottmentOut -= (dw_bytes_out_total - dw_bytes_out) * .20;
  1054.                 if(p_tns->m_dwByteAllottmentOut < dw_bytes_out_per_tns)        // oops, too much
  1055.                     p_tns->m_dwByteAllottmentOut = dw_bytes_out_per_thread_plus;
  1056.             }
  1057.  
  1058.             // same for incomming traffic
  1059.             if( p_tns->m_dwBytesIn >= p_tns->m_dwByteAllottmentIn)
  1060.                 p_tns->m_dwByteAllottmentIn = dw_bytes_in_per_soc;
  1061.             else
  1062.                 p_tns->m_dwByteAllottmentIn = dw_bytes_in_per_thread_plus;
  1063.                         
  1064.             p_tns = p_tns->next;
  1065.         }
  1066.  
  1067.         // * redistribute any allowance left over from slow socks.
  1068.  
  1069.         // * check for any socks over allotting their share, and how many total
  1070.         // * connections there, are, and deside whether to drop on or not.
  1071.  
  1072.         // * alternativly, filter packets to lower bandwidth consumtion.
  1073.     }
  1074.  
  1075.     for(p_soc = NodeList; p_soc != NULL;)
  1076.     {
  1077.         p_soc->m_dwBytesIn = 0;
  1078.         p_soc->m_dwBytesOut = 0;
  1079.  
  1080.         // give a chance to proccess more of the packets in the qeue
  1081.         p_soc->ProccessPacketQueue();
  1082.         
  1083.         p_soc = p_soc->next;
  1084.     }
  1085.  
  1086.  
  1087.     for(p_tns = TransferList; p_tns != NULL;)
  1088.     {
  1089.         p_tns->m_dwBytesIn = 0;
  1090.         p_tns->m_dwBytesOut = 0;
  1091.         
  1092.         p_tns = p_tns->next;
  1093.     }
  1094.  
  1095. }
  1096.  
  1097.